package it.pride.primefacesShowcase.service;

import it.pride.primefacesShowcase.filters.Filter;
import it.pride.primefacesShowcase.model.User;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.primefaces.model.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by IntelliJ IDEA.
 * User: lbonacina
 * Date: 25/07/11
 * Time: 15.59
 */
@Service("userService")
public class UserServiceImpl extends ServiceDefaultImpl implements UserService {

    private Logger logger = Logger.getLogger(this.getClass().getName());

    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

    @Override
    @Transactional(readOnly = true)
    @SuppressWarnings(value = "unchecked")
    public List<User> findAll() {
        return (List<User>) getCurrentSession().createCriteria(User.class).list();
    }

    @Override
    @Transactional(readOnly = true)
    public User findById(Long id) {
        return (User) getCurrentSession().get(User.class, id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<String> findAllCities() {
        return (List<String>) getCurrentSession().createCriteria(User.class).setProjection(Projections.distinct(Projections.property("city"))).addOrder(Order.asc("city")).list();
    }

    /**
     * 
     * @param first
     * @param pageSize
     * @param sortField
     * @param sortOrder
     * @param filters
     * @return 
     */
    @Override
    @Transactional(readOnly = true)
    public List<User> findForLazyDatatable(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {

        logger.debug("first : " + first);
        logger.debug("pageSize : " + pageSize);
        logger.debug("sortField : " + sortField);
        logger.debug("sortOrder : " + sortOrder);
        if (filters.isEmpty()) {
            logger.debug("filters are empty");
        }
        for (String key : filters.keySet()) {
            logger.debug("filter : key=" + key + ", value=" + filters.get(key));
        }

        Criteria crit = getCurrentSession().createCriteria(User.class);

        if ((sortField != null) & (sortOrder != SortOrder.UNSORTED)) {
            if (sortOrder == SortOrder.ASCENDING) {
                crit.addOrder(Order.asc(sortField));
            }
            else {
                crit.addOrder(Order.desc(sortField));
            }
        }

        crit = addCriteriaFromFilters(crit, filters, null);

        crit.setFirstResult(first).setMaxResults(pageSize);

        return crit.list();
    }

    /**
     * 
     * @param filters
     * @return 
     */
    @Override
    @Transactional(readOnly = true)
    public int countForLazyDatatable(Map<String, String> filters) {

        Criteria crit = getCurrentSession().createCriteria(User.class);

        crit = addCriteriaFromFilters(crit, filters, null);

        Long l = (Long) crit.setProjection(Projections.rowCount()).uniqueResult();

        logger.debug("record cound : " + l);

        return l.intValue();
    }

    /**
     * 
     * @param first
     * @param pageSize
     * @param sortField
     * @param sortOrder
     * @param filters
     * @param additionalFilters
     * @return 
     */
    @Override
    @Transactional(readOnly = true)
    public List<User> findForExtLazyDatatable(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters, List<Filter> additionalFilters) {

        logger.debug("first : " + first);
        logger.debug("pageSize : " + pageSize);
        logger.debug("sortField : " + sortField);
        logger.debug("sortOrder : " + sortOrder);
        if ( ( filters == null ) || ( filters.isEmpty() ) ) {
            logger.debug("filters are empty");
        }
        else {
            for (String key : filters.keySet()) {
                logger.debug("filter : key=" + key + ", value=" + filters.get(key));
            }
        }
        if ( ( additionalFilters == null ) || ( additionalFilters.isEmpty() ) ) {
            logger.debug("additional filters are empty");
        }
        else {
            for ( Filter f : additionalFilters ) 
                logger.debug("additional filter : " + f.toString());
        }

        Criteria crit = getCurrentSession().createCriteria(User.class);

        if ((sortField != null) & (sortOrder != SortOrder.UNSORTED)) {
            if (sortOrder == SortOrder.ASCENDING) {
                crit.addOrder(Order.asc(sortField));
            }
            else {
                crit.addOrder(Order.desc(sortField));
            }
        }

        crit = addCriteriaFromFilters(crit, filters, additionalFilters);
        crit.setFirstResult(first).setMaxResults(pageSize);

        return crit.list();
    }

    /**
     * 
     * @param filters
     * @param additionalFilters
     * @return 
     */
    @Override
    @Transactional(readOnly = true)
    public int countForExtLazyDatatable(Map<String, String> filters, List<Filter> additionalFilters) {

        Criteria crit = getCurrentSession().createCriteria(User.class);
        crit = addCriteriaFromFilters(crit, filters, additionalFilters);
        Long l = (Long) crit.setProjection(Projections.rowCount()).uniqueResult();
        return l.intValue();
    }

    /**
     * @param crit
     * @param filters
     * @param additionalFilters
     * @return 
     */
    private Criteria addCriteriaFromFilters(Criteria crit, Map<String, String> filters, List<Filter> additionalFilters) {

        if (filters != null) {
            for (String key : filters.keySet()) {
                Object value = filters.get(key);
                if (value != null) {
                    String valueExt = value + "%";
                    logger.debug("filter ( key : " + key + ", value : " + valueExt + " )");
                    crit.add(Restrictions.like(key, valueExt));
                }
            }
        }

        if (additionalFilters != null) {
            for (Filter f : additionalFilters) {
                crit.add(f.getCriterion());
            }
        }

        return crit;
    }
}
